package com.speljohan.rsbot.bot;

import java.awt.AWTPermission;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilePermission;
import java.net.JarURLConnection;
import java.net.SocketPermission;
import java.net.URL;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.PropertyPermission;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author Alex
 */
public final class RunescapeLoader extends ClassLoader {
	public static String SignLinkClassName = "";
	public static byte[] getPackedRunescapeJar() {
		try {
			final ByteArrayOutputStream baos = new ByteArrayOutputStream();
			final FileInputStream fis = new FileInputStream("RSBot.dat");
			int x;
			while ((x = fis.read()) != -1) {
				baos.write(x);
			}
			final byte[] data = baos.toByteArray();
			// We need to return an unscrambled array!
			return data;
			// return unscrambler(data);
		} catch (final Exception e) {
			System.err.println("Couldn't find RSBot.dat\r\nPlease download again!");
			return null;
		}
	}
	public final HashMap<String, byte[]> classes = new HashMap<String, byte[]>();
	private CodeSource codeSource;

	private ProtectionDomain domain;

	public RunescapeLoader(final String jarFile) {
		try {
			codeSource = new CodeSource(new URL("http://runescape.com/"),(CodeSigner[])null);
			domain = new ProtectionDomain(codeSource,getPermissions());
			final File file = new File(jarFile);
			/*for (File f : file.listFiles()) {
				String name = f.getName();
				if (name.endsWith(".class")) {
					byte buffer[] = new byte[1024];
					ByteArrayOutputStream baos = new ByteArrayOutputStream();
					int len = -1;
					BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
					while ((len = bis.read(buffer, 0, 1024)) != -1) baos.write(buffer, 0, len);
					bis.close();
					buffer = baos.toByteArray();

					String classname = name.substring(0,name.indexOf("."));
					if (classname.equals("bi")) {
						SignLinkClassName = classname;
					}
					classes.put(classname, buffer);
				}
			}*/
			final URL url = new URL("jar:" + file.toURI().toURL() + "!/");
			final JarURLConnection connection = (JarURLConnection) url.openConnection();
			final JarFile jar = connection.getJarFile();
			final Enumeration<JarEntry> entries = jar.entries();
			while (entries.hasMoreElements()) {
				final JarEntry entry = entries.nextElement();
				final String name = entry.getName();
				if (name.endsWith(".class")) {
					final int size = (int) entry.getSize();
					final byte buffer[] = new byte[size];
					final DataInputStream in = new DataInputStream(jar
							.getInputStream(entry));
					in.readFully(buffer);
					in.close();

					final String classname = name.substring(
							name.startsWith("[sl]") ? 4 : 0, name.lastIndexOf("."));
					if (name.startsWith("[sl]")) {
						RunescapeLoader.SignLinkClassName = classname;
					}

					classes.put(classname, buffer);
				}
			}
			//Permissions ps = new Permissions();
			//domain = new ProtectionDomain(null,ps);
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	private Permissions getPermissions() {
		final Permissions ps = new Permissions();
		ps.add(new AWTPermission("accessEventQueue"));
		ps.add(new PropertyPermission("user.home","read"));
		ps.add(new PropertyPermission("java.vendor","read"));
		ps.add(new PropertyPermission("java.version","read"));
		ps.add(new PropertyPermission("os.name","read"));
		ps.add(new PropertyPermission("os.arch","read"));
		ps.add(new PropertyPermission("os.version","read"));
		ps.add(new SocketPermission("*"/*.runescape.com"*/,"connect,resolve"));//quick fix TODO FIXME
		String uDir = System.getProperty("user.home");
		if(uDir != null) {
			uDir += "/";
		} else {
			uDir = "~/";
		}
		final String[] dirs = {"c:/rscache/", "/rscache/", "c:/windows/", "c:/winnt/",
				"c:/", uDir, "/tmp/", "."};
		// If "." fails then System.getProperty("user.dir") should work
		final String[] rsDirs = {".jagex_cache_32", ".file_store_32"};
		for (String dir : dirs) {
			final File f = new File(dir);
			ps.add(new FilePermission(dir,"read"));
			if (!f.exists()) {
				continue;
			}
			dir = f.getPath();
			for (final String rsDir : rsDirs) {
				ps.add(new FilePermission(dir + File.separator + rsDir + File.separator + "-","read"));
				ps.add(new FilePermission(dir + File.separator + rsDir + File.separator + "-","write"));
			}
		}
		Calendar.getInstance();
		//TimeZone.getDefault();//Now the default is set they don't need permission
		//ps.add(new FilePermission())
		ps.setReadOnly();
		return ps;
	}

	@Override
	public final Class<?> loadClass(String name) throws ClassNotFoundException {
		if (name.equals("SignLink")) {
			name = RunescapeLoader.SignLinkClassName;
		}
		if (classes.containsKey(name)) {
			final byte buffer[] = classes.remove(name);
			return defineClass(name, buffer, 0, buffer.length,domain);
		}

		return super.loadClass(name);
	}

}
